package com.gitee.chessboard.manager;

import com.gitee.chessboard.annotations.DictionaryConstant;
import com.gitee.chessboard.annotations.DictionaryEnum;
import com.gitee.chessboard.jdbc.JdbcManager;
import com.gitee.chessboard.jdbc.executor.SqlExecutor;
import com.gitee.chessboard.model.dictionary.Dictionary;
import com.gitee.chessboard.model.word.Word;
import com.gitee.chessboard.parser.DictionaryParser;
import com.gitee.chessboard.scan.ScanManager;
import com.gitee.chessboard.scan.discern.AnnotationDiscernPortion;
import com.gitee.chessboard.scan.discern.DiscernHandler;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典管理器的抽象实现
 *
 * @author 敲代码的旺财
 * @date 2021/11/18 9:37
 */
public abstract class AbstractDictionaryManager implements DictionaryManager {
    /**
     * 枚举分析器
     */
    DictionaryParser enumDictionaryParser;
    /**
     * 常量分析器
     */
    DictionaryParser constantDictionaryParser;

    /**
     * 字典的实现类
     */
    String dictionaryClazz;

    /**
     * 词的实现类
     */
    String wordClazz;

    /**
     * 需要转换的枚举类
     */
    List<Class<?>> enums;

    /**
     * 需要转换的常量类
     */
    List<Class<?>> constant;

    /**
     * 数据库控制器
     */
    JdbcManager jdbcManager;

    /**
     * 扫描控制器
     */
    ScanManager scanManager;

    /**
     * 扫描范围
     */
    String scanPath;

    /**
     * 字典集合
     */
    List<Dictionary> dictionaries;

    /**
     * 用于通过字典编码搜索字典集合
     */
    Map<String, Dictionary> dictionaryCodeSearch;

    /**
     * 用于通过词搜索字典
     */
    Map<Word, Dictionary> wordSearch;

    public AbstractDictionaryManager(JdbcManager jdbcManager) {
        this(jdbcManager, null);

    }


    public AbstractDictionaryManager(JdbcManager jdbcManager, String scanPath) {
        this(jdbcManager, scanPath
                , "com.gitee.chessboard.model.dictionary.DefaultDictionary"
                , "com.gitee.chessboard.model.word.DefaultWord");

    }

    public AbstractDictionaryManager(JdbcManager jdbcManager, String scanPath, String dictionaryClazz, String wordClazz) {
        this(jdbcManager, scanPath, dictionaryClazz, wordClazz, new ArrayList<>(), new ArrayList<>());
    }

    public AbstractDictionaryManager(JdbcManager jdbcManager, String scanPath, String dictionaryClazz, String wordClazz
            , List<Class<?>> enums, List<Class<?>> constant) {
        this.jdbcManager = jdbcManager;
        this.scanPath = scanPath;
        this.dictionaryClazz = dictionaryClazz;
        this.wordClazz = wordClazz;
        this.enums = enums;
        this.constant = constant;
    }

    /**
     * 用于刷新搜索缓存
     */
    void refreshSearch() {
        refreshDictionaryCodeSearch();
        refreshWordSearch();
    }

    /**
     * 刷新字典编码搜索缓存
     */
    void refreshDictionaryCodeSearch() {
        if (dictionaries == null || dictionaries.size() == 0) {
            return;
        }
        this.dictionaryCodeSearch = this.dictionaries.stream()
                .collect(Collectors.toMap(Dictionary::getDictionaryCode, m -> m));
    }

    /**
     * 刷新词编码搜索缓存
     */
    void refreshWordSearch() {
        if (dictionaries == null || dictionaries.size() == 0) {
            return;
        }
        Map<List<Word>, Dictionary> wordMap = this.dictionaries.stream()
                .collect(Collectors.toMap(Dictionary::get, m -> m));
        this.wordSearch = new HashMap<>();
        for (Map.Entry<List<Word>, Dictionary> entry : wordMap.entrySet()) {
            for (Word word : entry.getKey()) {
                wordSearch.put(word, entry.getValue());
            }
        }
    }

    /**
     * 初始化
     */
    @Override
    public void init() {
        if (enumDictionaryParser == null) {
            throw new RuntimeException("请设置枚举分析器");
        }
        if (constantDictionaryParser == null) {
            throw new RuntimeException("请设置常量分析器");
        }
        //初始化扫描器
        if (this.scanManager == null) {
            this.scanManager = getDefaultScanManager();
        }
        SqlExecutor sqlExecutor = jdbcManager.getSqlExecutor();
        //实例化字典和词(创建表）
        try {
            Dictionary dictionary = (Dictionary) Class.forName(dictionaryClazz).newInstance();
            Word word = (Word) Class.forName(wordClazz).newInstance();
            sqlExecutor.createTable(dictionary);
            sqlExecutor.createTable(word);

            List<Dictionary> parsers = new ArrayList<>();
            //处理枚举类
            for (Class<?> anEnum : getEnums()) {
                parsers.add(enumDictionaryParser.parser(anEnum));

            }
            for (Class<?> constant : getConstant()) {
                parsers.add(constantDictionaryParser.parser(constant));
            }

            for (Dictionary parser : parsers) {
                parser.saveSelf();
            }

            //读取数据
            //获取所有的词
            List<Word> wordAll = sqlExecutor.getAll(word);
            //获取所有的字典
            List<Dictionary> dictionaryAll = sqlExecutor.getAll(dictionary);


            //重新创建字典和词
            dictionaryAll.forEach(m -> m.setDictionaryManager(this));
            Map<String, Dictionary> dictionaryMap = dictionaryAll.stream()
                    .collect(Collectors.toMap(Dictionary::getDictionaryCode, m -> m));
            for (Word wordNode : wordAll) {
                wordNode.setDictionaryManager(this);
                dictionaryMap.get(wordNode.getDictionaryCode()).add(wordNode);
            }
            this.dictionaries = dictionaryAll;

            //刷新搜索
            refreshSearch();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setScanManager(ScanManager scanManager) {
        this.scanManager = scanManager;
    }

    /**
     * 获取默认的扫描控制器
     *
     * @return 扫描控制器
     */
    private ScanManager getDefaultScanManager() {
        if(this.scanManager != null){
            return this.scanManager;
        }
        if (scanPath == null || scanPath.length() == 0) {
            return null;
        }

        //注解识别器
        AnnotationDiscernPortion dictionaryConstantAnnotation = new AnnotationDiscernPortion();
        dictionaryConstantAnnotation.targetDescribe(DictionaryConstant.class);

        AnnotationDiscernPortion dictionaryEnumAnnotation = new AnnotationDiscernPortion();
        dictionaryEnumAnnotation.targetDescribe(DictionaryEnum.class);

        //创建扫描控制器
        ScanManager scanManager = new ScanManager();
        DiscernHandler discernHandler = scanManager.getDiscernHandler();
        discernHandler.addDiscern(dictionaryConstantAnnotation);
        discernHandler.addDiscern(dictionaryEnumAnnotation);
        scanManager.discern(scanPath);

        //将扫描到的内容添加到缓存中
        getEnums().addAll(dictionaryEnumAnnotation.getDiscernResults());
        getConstant().addAll(dictionaryConstantAnnotation.getDiscernResults());
        return scanManager;
    }

    /**
     * 保存字典
     *
     * @param dictionary 字典
     */
    @Override
    public void save(Dictionary dictionary) {
        SqlExecutor sqlExecutor = jdbcManager.getSqlExecutor();
        sqlExecutor.insertOrUpdate(dictionary);
        for (Word word : dictionary.get()) {
            word.saveSelf();
        }
        refreshSearch();
    }

    /**
     * 保存词
     *
     * @param word 词
     */
    @Override
    public void save(Word word) {
        SqlExecutor sqlExecutor = jdbcManager.getSqlExecutor();
        sqlExecutor.insertOrUpdate(word);
        refreshWordSearch();
    }

    /**
     * 删除字典
     *
     * @param dictionary 字典
     */
    @Override
    public void del(Dictionary dictionary) {
        SqlExecutor sqlExecutor = jdbcManager.getSqlExecutor();
        //删除字典
        sqlExecutor.delete(dictionary);
        refreshSearch();
    }

    /**
     * 删除词
     *
     * @param word 词
     */
    @Override
    public void del(Word word) {
        refreshSearch();
    }

    /**
     * 获取一个全新的词
     */
    @Override
    public Word getNewWord() {
        try {
            return (Word) Class.forName(wordClazz)
                    .getConstructor(DictionaryManager.class)
                    .newInstance(this);
        } catch (ClassNotFoundException | NoSuchMethodException
                | InstantiationException | IllegalAccessException
                | InvocationTargetException e) {
            throw new RuntimeException("创建词失败", e);
        }
    }

    /**
     * 获取一个全新的字典
     */
    @Override
    public Dictionary getNewDictionary(List<Word> words) {
        try {
            return (Dictionary) Class.forName(dictionaryClazz)
                    .getConstructor(List.class, DictionaryManager.class)
                    .newInstance(words, this);
        } catch (ClassNotFoundException | NoSuchMethodException
                | InstantiationException | IllegalAccessException
                | InvocationTargetException e) {
            throw new RuntimeException("创建字典失败", e);
        }
    }

    /**
     * 获取一个全新的字典
     */
    @Override
    public Dictionary getNewDictionary() {
        try {
            return (Dictionary) Class.forName(dictionaryClazz)
                    .getConstructor(DictionaryManager.class)
                    .newInstance(this);
        } catch (ClassNotFoundException | NoSuchMethodException
                | InstantiationException | IllegalAccessException
                | InvocationTargetException e) {
            throw new RuntimeException("创建字典失败", e);
        }
    }

    /**
     * 获取所有字典
     *
     * @return 字典列表
     */
    @Override
    public List<Dictionary> get() {
        return dictionaries;
    }

    /**
     * 根据字典编码获取字典
     *
     * @param dictionaryCode 字典编码
     * @return 字典
     */
    @Override
    public Dictionary get(String dictionaryCode) {
        if (dictionaryCodeSearch == null) {
            return null;
        }
        return dictionaryCodeSearch.get(dictionaryCode);
    }

    /**
     * 根据词获取字典
     *
     * @param word 词
     * @return 字典列表  因为词只保证在一个字典下不重复，所以可能会获取到多个字典
     */
    @Override
    public Dictionary getByWord(Word word) {
        return wordSearch.get(word);
    }

    /**
     * 获取枚举
     */
    public List<Class<?>> getEnums() {
        return enums;
    }

    /**
     * 设置枚举
     *
     * @param enums 枚举集合
     */
    public void setEnums(List<Class<?>> enums) {
        this.enums = enums;
    }

    /**
     * 获取常量
     */
    public List<Class<?>> getConstant() {
        return constant;
    }

    /**
     * 设置常量
     *
     * @param constant 常量集合
     */
    public void setConstant(List<Class<?>> constant) {
        this.constant = constant;
    }

    /**
     * 获取枚举处理器
     */
    public DictionaryParser getEnumDictionaryParser() {
        return enumDictionaryParser;
    }

    /**
     * 设置枚举处理器
     */
    public void setEnumDictionaryParser(DictionaryParser enumDictionaryParser) {
        this.enumDictionaryParser = enumDictionaryParser;
    }

    /**
     * 获取常量处理器
     */
    public DictionaryParser getConstantDictionaryParser() {
        return constantDictionaryParser;
    }

    /**
     * 设置常量处理器
     */
    public void setConstantDictionaryParser(DictionaryParser constantDictionaryParser) {
        this.constantDictionaryParser = constantDictionaryParser;
    }
}
